home *** CD-ROM | disk | FTP | other *** search
/ HPAVC / HPAVC CD-ROM.iso / pc / VGA_VUL3.ZIP / 3DLINES.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1995-08-01  |  13.1 KB  |  411 lines

  1. Program Rotations3d;  { Basic 3d-engine routines by Vulture / Outlaw Triad }
  2.  
  3. Uses Crt;             { Used units }
  4.  
  5. Const VGA = $0a000;   { VGA segment }
  6.       MaxLines = 12;  { Max number of lines to rotate }
  7.       Xoff: Integer = 256;     { Used to calculate vga-pos }
  8.       Yoff: Integer = 256;
  9.       Size = 25;      { Size of box }
  10.       Cube: Array[1..MaxLines,1..2,1..3] of Integer =  { Our object (box) }
  11.         (((-Size,-Size,-Size),(Size,-Size,-Size)),
  12.          ((-Size,-Size,-Size),(-Size,Size,-Size)),
  13.          ((-Size,Size,-Size),(Size,Size,-Size)),
  14.          ((Size,-Size,-Size),(Size,Size,-Size)),
  15.          ((-Size,-Size,Size),(Size,-Size,Size)),
  16.          ((-Size,-Size,Size),(-Size,Size,Size)),
  17.          ((-Size,Size,Size),(Size,Size,Size)),
  18.          ((Size,-Size,Size),(Size,Size,Size)),
  19.          ((-Size,-Size,Size),(-Size,-Size,-Size)),
  20.          ((-Size,Size,Size),(-Size,Size,-Size)),
  21.          ((Size,Size,Size),(Size,Size,-Size)),
  22.          ((Size,-Size,Size),(Size,-Size,-Size)));
  23.  
  24. Var Sine: Array[0..255] of Integer;    { Contains sine&cosine values }
  25.  
  26.     Lines: Array[1..MaxLines,1..2,1..2] of Integer;  { Holds x,y coords of lines }
  27.  
  28.     OldLines: Array[1..MaxLines,1..2,1..2] of Integer; { Old lines of object }
  29.  
  30.     X,Y,Z: Integer;                { Variables for formula }
  31.  
  32.     Xt,Yt,Zt: Integer;             { Temporary variables for x,y,z }
  33.  
  34.     XAngle,YAngle,ZAngle: Byte;    { Angles to rotate around }
  35.  
  36.     DeltaX,DeltaY,DeltaZ: Byte;    { Amound angles are increased each time }
  37.  
  38.     Zoff: Integer;                 { Distance from viewer }
  39.  
  40.     XSin,XCos: Integer;            { Sine and cosine of angle to rotate around }
  41.     YSin,YCos: Integer;
  42.     ZSin,ZCos: Integer;
  43.  
  44.     Mx,My: Integer;                { Middle of the screen }
  45.  
  46.     ScreenX, ScreenY: Integer;     { Screenpositions of 3d-point }
  47.  
  48.     Direction: Boolean;            { Direction of object }
  49.  
  50.     Looping: Integer;              { Variable for moving object }
  51.  
  52. Procedure VideoMode(Mode: Byte); ASSEMBLER;
  53. Asm
  54.   mov  ah,00
  55.   mov  al,Mode
  56.   int  10h
  57. End;
  58.  
  59. Procedure SetPixel(X,Y:Integer;Color:Byte;Where:Word); ASSEMBLER;
  60. Asm                         { TP automatically pushes and pops ES }
  61.   mov  ax,[Where]           { Move destination in AX }
  62.   mov  es,ax                { es => points to VGA or virtual screen }
  63.   mov  di,Y                 { Move Y into DI }
  64.   mov  ax,Y                 { Move Y into AX }
  65.   shl  di,8                 { DI := DI * 256 }
  66.   shl  ax,6                 { AX := AX * 64 }
  67.   add  di,ax                { DI := Y * 320 }
  68.   mov  ax,X                 { Move X into AX }
  69.   add  di,ax                { DI = X + Y   final location }
  70.   mov  al,Color             { Set color }
  71.   stosb                     { = mov  byte ptr es:[di],al => Place the dot }
  72. End;
  73.  
  74. Procedure WaitRetrace; ASSEMBLER;  { Waits for Vertical Retrace to reduce flicker }
  75. label l1, l2;
  76. Asm
  77.    mov  dx,3DAh
  78. l1:
  79.    in   al,dx
  80.    and  al,08h
  81.    jnz  l1
  82. l2:
  83.    in   al,dx
  84.    and  al,08h
  85.    jz   l2
  86. End;
  87.  
  88. Procedure CalcSine;                   { Guess what this does... ;) }
  89. Var I,Out: Integer;
  90.     An: Real;
  91. Begin
  92.   For I := 0 to 255 Do                { 256 values }
  93.   Begin
  94.     An := I*(2*pi / 256);             { 2*pi coz of radians! }
  95.     Out := Round(Sin(An)*256);
  96.     Sine[I] := Out;                   { Save into array }
  97.   End;
  98. End;
  99.  
  100. Procedure Line(X1,Y1,X2,Y2:Integer;Color:Byte;Where:Word);
  101.   Function sgn(a:real):integer;       { Nested function }
  102.   Begin
  103.     if a>0 then sgn := +1;
  104.     if a<0 then sgn := -1;
  105.     if a=0 then sgn := 0;
  106.   End;
  107. Var i,s,d1x,d1y,d2x,d2y,u,v,m,n:integer;
  108. Begin
  109.   u := X2 - X1;
  110.   v := Y2 - Y1;
  111.   d1x := SGN(u);
  112.   d1y := SGN(v);
  113.   d2x := SGN(u);
  114.   d2y := 0;
  115.   m := ABS(u);
  116.   n := ABS(v);
  117.   If not (M>N) then
  118.   Begin
  119.     d2x := 0;
  120.     d2y := SGN(v);
  121.     m := ABS(v);
  122.     n := ABS(u);
  123.   End;
  124.   s := m shr 1;
  125.   For i := 0 to m Do
  126.   Begin
  127.     Setpixel(X1,Y1,Color,Where);
  128.     s := s + n;
  129.     IF not (s<m) Then
  130.     Begin
  131.       s := s - m;
  132.       X1 := X1 + d1x;
  133.       Y1 := Y1 + d1y;
  134.     End
  135.     Else
  136.     Begin
  137.       X1 := X1 + d2x;
  138.       Y1 := Y1 + d2y;
  139.     End;
  140.   End;
  141. End;
  142.  
  143. Procedure UpdateVars;      { Used to fly around the screen }
  144. Begin
  145.   If Direction then If Mx < 275 then INC(Mx) else Direction := False
  146.     else If Mx > 45 then DEC(Mx) else Direction := True;
  147. End;
  148.  
  149. Procedure SetRotation;          { Calculates new angles to rotate around }
  150. Begin
  151.   If DeltaX > 0 then XAngle := (Xangle+DeltaX) Mod 256; { Angles stop at 256 }
  152.   If DeltaY > 0 then YAngle := (Yangle+DeltaY) Mod 256;
  153.   If DeltaZ > 0 then ZAngle := (Zangle+DeltaZ) Mod 256;
  154. End;
  155.  
  156. Procedure GetSineCos;
  157. Begin
  158.   Xsin := Sine[Xangle];                  { Grab sine from sinetable }
  159.   Xcos := Sine[(Xangle+64) Mod 256];     { Add 64 to get cosine }
  160.   Ysin := Sine[Yangle];
  161.   Ycos := Sine[(Yangle+64) Mod 256];
  162.   Zsin := Sine[Zangle];
  163.   Zcos := Sine[(Zangle+64) Mod 256];
  164. End;
  165.  
  166. Procedure GetOrgXYZ(Current,Place: Integer);
  167. Begin
  168.   X := Cube[Current,Place,1];      { Grabs our original x,y,z values }
  169.   Y := Cube[Current,Place,2];
  170.   Z := Cube[Current,PLace,3];
  171. End;
  172.  
  173. Procedure RotatePoint; ASSEMBLER;  { Uses assembler-code for speed }
  174. { Rotates a point around x,y,z. The degrees rotated around are calculated
  175.   using the SetRotation procedure. The (co)sine values are grabbed using
  176.   the GetSineCos procedure. We also need the original x,y,z values of the
  177.   current 3d-point. These are grabbed using the GetOrgXYZ procedure. }
  178. Asm
  179. { Rotate around x-axis }
  180. { YT = Y * COS(xang) - Z * SIN(xang) / 256 }
  181. { ZT = Y * SIN(xang) + Z * COS(xang) / 256 }
  182. { Y = YT }
  183. { Z = ZT }
  184.     pusha
  185.     mov     ax,[Y]
  186.     mov     bx,[XCos]
  187.     imul    bx               { ax = Y * Cos(xang) }
  188.     mov     bp,ax
  189.     mov     ax,[Z]
  190.     mov     bx,[XSin]
  191.     imul    bx               { ax = Z * Sin(xang) }
  192.     sub     bp,ax            { bp = Y * Cos(xang) - Z * Sin(xang) }
  193.     sar     bp,8             { bp = Y * Cos(xang) - Z * Sin(xang) / 256 }
  194.     mov     [Yt],bp
  195.  
  196.     mov     ax,[Y]
  197.     mov     bx,[XSin]
  198.     imul    bx               { ax = Y * Sin(xang) }
  199.     mov     bp,ax
  200.     mov     ax,[Z]
  201.     mov     bx,[XCos]
  202.     imul    bx               { ax = Z * Cos(xang) }
  203.     add     bp,ax            { bp = Y * SIN(xang) + Z * COS(xang) }
  204.     sar     bp,8             { bp = Y * SIN(xang) + Z * COS(xang) / 256 }
  205.     mov     [Zt],bp
  206.  
  207.     mov     ax,[Yt]          { Switch values }
  208.     mov     [Y],ax
  209.     mov     ax,[Zt]
  210.     mov     [Z],ax
  211.  
  212. { Rotate around y-axis }
  213. { XT = X * COS(yang) - Z * SIN(yang) / 256 }
  214. { ZT = X * SIN(yang) + Z * COS(yang) / 256 }
  215. { X = XT }
  216. { Z = ZT }
  217.  
  218.     mov     ax,[X]
  219.     mov     bx,[YCos]
  220.     imul    bx               { ax = X * Cos(yang) }
  221.     mov     bp,ax
  222.     mov     ax,[Z]
  223.     mov     bx,[YSin]
  224.     imul    bx               { ax = Z * Sin(yang) }
  225.     sub     bp,ax            { bp = X * Cos(yang) - Z * Sin(yang) }
  226.     sar     bp,8             { bp = X * Cos(yang) - Z * Sin(yang) / 256 }
  227.     mov     [Xt],bp
  228.  
  229.     mov     ax,[X]
  230.     mov     bx,[YSin]
  231.     imul    bx               { ax = X * Sin(yang) }
  232.     mov     bp,ax
  233.     mov     ax,[Z]
  234.     mov     bx,[YCos]
  235.     imul    bx               { ax = Z * Cos(yang) }
  236.     add     bp,ax            { bp = X * SIN(yang) + Z * COS(yang) }
  237.     sar     bp,8             { bp = X * SIN(yang) + Z * COS(yang) / 256 }
  238.     mov     [Zt],bp
  239.  
  240.     mov     ax,[Xt]          { Switch values }
  241.     mov     [X],ax
  242.     mov     ax,[Zt]
  243.     mov     [Z],ax
  244.  
  245. { Rotate around z-axis }
  246. { XT = X * COS(zang) - Y * SIN(zang) / 256 }
  247. { YT = X * SIN(zang) + Y * COS(zang) / 256 }
  248. { X = XT }
  249. { Y = YT }
  250.  
  251.     mov     ax,[X]
  252.     mov     bx,[ZCos]
  253.     imul    bx               { ax = X * Cos(zang) }
  254.     mov     bp,ax
  255.     mov     ax,[Y]
  256.     mov     bx,[ZSin]
  257.     imul    bx               { ax = Y * Sin(zang) }
  258.     sub     bp,ax            { bp = X * Cos(zang) - Y * Sin(zang) }
  259.     sar     bp,8             { bp = X * Cos(zang) - Y * Sin(zang) / 256 }
  260.     mov     [Xt],bp
  261.  
  262.     mov     ax,[X]
  263.     mov     bx,[ZSin]
  264.     imul    bx               { ax = X * Sin(zang) }
  265.     mov     bp,ax
  266.     mov     ax,[Y]
  267.     mov     bx,[ZCos]
  268.     imul    bx               { ax = Y * Cos(zang) }
  269.     add     bp,ax            { bp = X * SIN(zang) + Y * COS(zang) }
  270.     sar     bp,8             { bp = X * SIN(zang) + Y * COS(zang) / 256 }
  271.     mov     [Yt],bp
  272.  
  273.     mov     ax,[Xt]          { Switch values }
  274.     mov     [X],ax
  275.     mov     ax,[Yt]
  276.     mov     [Y],ax
  277.     popa
  278. End;
  279.  
  280. Procedure CalcPos; ASSEMBLER;
  281. { This procedure calculates the X, Y position of the rotated 3d-point on
  282.   the vga-screen. These values are then stored in an array. }
  283. Asm
  284.     pusha
  285.     mov     ax,[Xoff]           { Xoff*X / Z+Zoff = screen x }
  286.     mov     bx,[X]
  287.     imul    bx
  288.     mov     bx,[Z]
  289.     add     bx,[Zoff]           { Distance }
  290.     idiv    bx
  291.     add     ax,[Mx]             { Center on screen }
  292.     mov     bp,ax
  293.     mov     [ScreenX],ax
  294.  
  295.     mov     ax,[Yoff]           { Yoff*Y / Z+Zoff = screen y }
  296.     mov     bx,[Y]
  297.     imul    bx
  298.     mov     bx,[Z]
  299.     add     bx,[Zoff]           { Distance }
  300.     idiv    bx
  301.     add     ax,[My]             { Center on screen }
  302.     mov     [ScreenY],ax
  303.     popa
  304. End;
  305.  
  306. Procedure RotateAllStuff;        { Rotates all points (lines) }
  307. Var Loop1,Loop2: Integer;
  308. Begin
  309.   For Loop1 := 1 to MaxLines Do  { Do all object lines }
  310.   Begin
  311.     For Loop2 := 1 to 2 Do       { Both 3d-points of line }
  312.     Begin
  313.       GetOrgXYZ(Loop1,Loop2);    { Get the original x,y,z values }
  314.       RotatePoint;               { Rotate the point around x,y,z }
  315.       CalcPos;                   { And calc the screenposition }
  316.       Lines[Loop1,Loop2,1] := ScreenX;    { Save screenpositions }
  317.       Lines[Loop1,Loop2,2] := ScreenY;
  318.     End;
  319.   End;
  320. End;
  321.  
  322. Procedure DeleteAll(Color: Byte);   { Deletes object on the screen }
  323. Var Loop1: Integer;
  324.     X1,Y1,X2,Y2: Integer;
  325. Begin
  326.   For Loop1 := 1 to MaxLines Do
  327.   Begin
  328.     X1 := OldLines[Loop1,1,1];      { Set end-points of line }
  329.     Y1 := OldLines[Loop1,1,2];
  330.     X2 := OldLines[Loop1,2,1];
  331.     Y2 := OldLines[Loop1,2,2];
  332.     Line(X1,Y1,X2,Y2,Color,VGA);    { Erase old line... }
  333.   End;
  334. End;
  335.  
  336. Procedure ShowItAll(Color: Byte);   { Shows object on the screen }
  337. Var Loop1: Integer;
  338.     X1,Y1,X2,Y2: Integer;
  339. Begin
  340.   For Loop1 := 1 to MaxLines Do
  341.   Begin
  342.     X1 := Lines[Loop1,1,1];         { Set end-points of line }
  343.     Y1 := Lines[Loop1,1,2];
  344.     X2 := Lines[Loop1,2,1];
  345.     Y2 := Lines[Loop1,2,2];
  346.     OldLines[Loop1,1,1] := X1;      { Save for deletion }
  347.     OldLines[Loop1,1,2] := Y1;
  348.     OldLines[Loop1,2,1] := X2;
  349.     OldLines[Loop1,2,2] := Y2;
  350.     Line(X1,Y1,X2,Y2,Color,VGA);    { Draw new line }
  351.   End;
  352. End;
  353.  
  354. Begin                   { Main program }
  355.   ClrScr;
  356.   Writeln('                  3D-ENGINE by Vulture / Outlaw Triad.');
  357.   Writeln;
  358.   Writeln('This program will rotate a 3d-box on the vga-screen. It is a basic');
  359.   Writeln('example of how to do 3d rotations. Remember this is only one method.');
  360.   Writeln('There are many other ways to get 3d to work.');
  361.   Writeln;
  362.   Writeln('Hmm, still having some problems with the deletion of the object.');
  363.   Writeln('I guess it''s too fast thus showing only parts of the object on slow');
  364.   Writeln('machines (386sx?). Weird huh? Too fast on slow machines... confusing ;)');
  365.   Writeln('Anyway, it works fine on my 486dx so take a look at the source and');
  366.   Writeln('solve the problem yarselve coz I just don''t feel like optimizing a');
  367.   Writeln('program which serves only as an example. Besides that, this program');
  368.   Writeln('needs a lotta improvement anyway.');
  369.   Writeln;
  370.   Writeln('I have included some basic assembler-routines in this little code! ');
  371.   Writeln('The actual rotation is done in asm to gain speed. It''s not too fast');
  372.   Writeln('but fast enough for now. Goodluck to ye!');
  373.   Writeln;
  374.   Writeln;
  375.   Write('Press any key to enter 3d-zone...');
  376.   ReadKey;
  377.   CalcSine;
  378.   Mx := 160;
  379.   My := 100;            { Middle of the screen }
  380.   Direction := True;    { Go to the right first }
  381.   Xangle := 0;          { Set initial degrees }
  382.   Yangle := 0;
  383.   Xangle := 0;
  384.   DeltaX := 2;          { Degree factors }
  385.   DeltaY := 1;
  386.   DeltaZ := 1;
  387.   Zoff := 1024;         { Distance from viewer }
  388.   VideoMode($13);
  389.   For Looping := 1 to 256 Do
  390.   Begin
  391.     SetRotation;        { Set new rotation angles }
  392.     GetSineCos;         { Grab sine & cosine of those angles }
  393.     RotateAllStuff;     { Rotates all points/lines }
  394.     WaitRetrace;        { Do vertical retrace }
  395.     DeleteAll(0);       { Delete old lines }
  396.     ShowItAll(24);      { Show new stuff }
  397.     Dec(Zoff,3);        { Object moves towards viewer (untill Zoff = 256 }
  398.   End;
  399.   Repeat
  400.     SetRotation;        { Set new rotation angles }
  401.     GetSineCos;         { Grab sine & cosine of those angles }
  402.     UpdateVars;         { Used to fly around screen }
  403.     RotateAllStuff;     { Rotates all points/lines }
  404.     WaitRetrace;        { Do vertical retrace }
  405.     DeleteAll(0);       { Delete old lines }
  406.     ShowItAll(24);      { And show new stuff }
  407.   Until KeyPressed;
  408.   ReadKey;
  409.   VideoMode($3);
  410.   Writeln('Code By Vulture / Outlaw Triad');
  411. End.